package com.huage.courseplatform.satoken.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.huage.courseplatform.framework.utils.date.DateUtils;
import com.huage.courseplatform.framework.utils.EncryptUtil;
import com.huage.courseplatform.satoken.mapper.UserMapper;
import com.huage.courseplatform.satoken.model.entity.Role;
import com.huage.courseplatform.satoken.model.entity.User;
import com.huage.courseplatform.satoken.model.param.FormLoginPARAM;
import com.huage.courseplatform.satoken.model.vo.LoginVO;
import com.huage.courseplatform.satoken.service.LoginService;

import com.huage.courseplatform.satoken.service.RoleService;
import com.huage.courseplatform.satoken.service.UserService;
import com.huage.courseplatform.framework.utils.WechatUtil;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.util.List;
import java.util.concurrent.TimeUnit;

import static com.huage.courseplatform.framework.constant.StatusConstants.ACCOUNT_NORMAL;


@Service
public class LoginServiceImpl extends ServiceImpl<UserMapper, User> implements LoginService {

    @Resource
    private UserMapper userMapper;

    @Resource
    private UserService userService;

    @Resource
    private RoleService roleService;

    @Resource
    private RedisTemplate redisTemplate;


    @Override
    public LoginVO formLogin(FormLoginPARAM formLoginParam,String ip) {

        int loginCount  = 0;
        Object loginCountObj =  redisTemplate.opsForValue().get("LoginCount:username::"+formLoginParam.getUsername());
        if(loginCountObj!=null){
            loginCount = (Integer) loginCountObj;
        }
        Assert.isTrue(loginCount<5, "登录失败次数已达上限,请稍后再试");
        //添加失败次数
        redisTemplate.opsForValue().set("LoginCount:username::"+formLoginParam.getUsername(),loginCount+1, 30,TimeUnit.MINUTES);

        LoginVO loginVo = new LoginVO();
        User phoneUser = lambdaQuery().eq(User::getPhone, formLoginParam.getUsername()).one();
        User emailUser = lambdaQuery().eq(User::getEmail, formLoginParam.getUsername()).one();

        if (ObjectUtils.isEmpty(phoneUser) && ObjectUtils.isEmpty(emailUser)) {
            Assert.isTrue(false, "账号或密码错误");
        }

        if (ObjectUtils.isNotEmpty(phoneUser)) {
            String password = EncryptUtil.getInstance().MD5(formLoginParam.getPassword(),phoneUser.getPasswordSalt());
            Assert.isTrue(phoneUser.getStatus() == ACCOUNT_NORMAL, "账号状态异常，请联系管理员");
            Assert.isTrue(phoneUser.getPassword().equals(password), "账号或密码错误");
            BeanUtils.copyProperties(phoneUser, loginVo);
            // 回写ip 最后登录时间，数据到user
            User user = new User();
            user.setId(phoneUser.getId());
            user.setLastLoginTime(DateUtils.getTime());
            user.setIp(ip);
            userMapper.updateById(user);
            phoneUser.setLastLoginTime(DateUtils.getTime());
            phoneUser.setIp(ip);

            redisTemplate.delete("LoginCount:username::"+formLoginParam.getUsername());
            StpUtil.login(phoneUser.getId());
            loginVo.setAuthorization(StpUtil.getTokenInfo().getTokenValue());


            return loginVo;
        }
        if (ObjectUtils.isNotEmpty(emailUser)) {
            String password = EncryptUtil.getInstance().MD5(formLoginParam.getPassword(),emailUser.getPasswordSalt());
            Assert.isTrue(emailUser.getStatus() == ACCOUNT_NORMAL, "账号状态异常，请联系管理员");
            Assert.isTrue(emailUser.getPassword().equals(password), "账号或密码错误");
            BeanUtils.copyProperties(emailUser, loginVo);

            // 回写ip 最后登录时间，数据到user
            User user = new User();
            user.setId(emailUser.getId());
            user.setLastLoginTime(DateUtils.getTime());
            user.setIp(ip);
            userMapper.updateById(user);
            emailUser.setLastLoginTime(DateUtils.getTime());
            emailUser.setIp(ip);

            redisTemplate.delete("LoginCount:username::"+formLoginParam.getUsername());
            StpUtil.login(emailUser.getId());
            loginVo.setAuthorization(StpUtil.getTokenInfo().getTokenValue());
            return loginVo;
        }


        Assert.isTrue(true, "账号或密码错误");
        return loginVo;
    }

    @Override
    public LoginVO wxLogin(String code,String ip) {
        // 1.接收小程序发送的code
        // 2.开发者服务器 登录凭证校验接口 appi + appsecret + code
        JSONObject SessionKeyOpenId = WechatUtil.getSessionKeyOrOpenId(code);
        String openId = SessionKeyOpenId.getString("openid");
        String sessionKey = SessionKeyOpenId.getString("session_key");

        Assert.isTrue(!StringUtils.isEmpty(openId),"请求微信服务器错误:"+SessionKeyOpenId.getString("errmsg"));


        User loginUser = lambdaQuery().eq(User::getOpenId,openId).one();

        //首次登录小程序
        if(ObjectUtils.isEmpty(loginUser)){
            loginUser = new User();
            //注册账号
            loginUser.setOpenId(openId);
            loginUser.setStatus(ACCOUNT_NORMAL);
            userService.addUserAndRole(loginUser,null);
            //user = userService.getUserAndRoleById()
        }
        //回写ip 最后登录时间，数据到user
        User user = new User();
        user.setId(loginUser.getId());
        user.setLastLoginTime(DateUtils.getTime());
        user.setIp(ip);
        userMapper.updateById(user);
        loginUser.setLastLoginTime(DateUtils.getTime());
        loginUser.setIp(ip);

        StpUtil.login(loginUser.getId());
        List<Role> roleList = roleService.getRoleListByUserId(loginUser.getId());

        LoginVO loginVO = new LoginVO();
        loginVO.setRoleList(roleList);
        loginVO.setAuthorization(StpUtil.getTokenInfo().getTokenValue());

        BeanUtils.copyProperties(loginUser,loginVO);


        return loginVO;
    }

    @Override
    public void loginOutByToken(String token) {
        StpUtil.logoutByTokenValue(token);
    }

    @Override
    public void loginOutById(String userId) {
        StpUtil.logout(userId);
    }



}
